﻿#include "stdafx.h"
#include "script.h"
#include "thread_control.h"
#include "log.h"
#include "GameAppDlg.h"
#include "resource.h"
#include "LuaFun.h"

int gTime = 0;
int nCountTime = 0;
bool isGif = false;
int gnIndex = 0;
CString strLua;
lua_State* L = luaL_newstate();

unsigned WINAPI SubThread(PVOID pParam);
void CheckException(long index);

// 我们做暂停和恢复操作,就主要靠这个延时函数,要求脚本所有用到延时的地方，全部用这个，这样我们可以有很多机会去暂停线程
void ScriptDelay(long index, long time)
{
	// 判断是否有暂停和结束标记
	if (g_info[index].is_stop)
	{
		// 直接退出当前线程,退出前一定要在本线程内解绑,因为绑定模式0和2在线程外解绑的话会失败,导致解绑失败.
		if (g_info[index].dm)
		{
			g_info[index].dm->UnBindWindow();
		}
		_endthreadex(0);
	}

	if (g_info[index].is_pause)
	{
		g_info[index].thread_state = State_Pause;
		ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

		// 如果你想要在暂停时让用户可以操作,那么可以调用EnableBind,但是不要去调用LockInput,LockInput不是用来解除后台的,具体参考LockInput的说明
		if (g_info[index].dm)
		{
			g_info[index].dm->EnableBind(5);
		}

		// 我们暂停的方法是死循环,然后延时,而不是调用系统的接口
		// 这样开销最小,并且效率也还不错
		while (1)
		{
			if (!g_info[index].is_pause)
			{
				g_info[index].thread_state = State_Runing;
				ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

				// 开启后台
				if (g_info[index].dm)
				{
					g_info[index].dm->EnableBind(1);
				}
				break;
			}

			if (g_info[index].is_stop)
			{
				// 直接退出当前线程,退出前一定要在本线程内解绑,因为绑定模式0和2在线程外解绑的话会失败,导致解绑失败.
				if (g_info[index].dm)
				{
					g_info[index].dm->UnBindWindow();
				}
				_endthreadex(0);
			}

			Sleep(1);
		}
	}

	// 可能暂停,恢复时会让状态错乱,这里再判断一次
	if (g_info[index].thread_state != State_Runing)
	{
		g_info[index].thread_state = State_Runing;
		ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

		// 开启后台
		if (g_info[index].dm)
		{
			g_info[index].dm->EnableBind(1);
		}
	}

	Sleep(time);
}

void SetTaskState(long index, const TCHAR * state)
{
	_tcscpy(g_info[index].task_state, state);
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);
}

int show(lua_State *L) {
	CString str;
	str= lua_tostring(L, -1);
	g_main_cwnd->AppendText(str);
	return 0;
}

void LoadLua() {
	CFile fileR;
	CString strFile = L"";
	if (!fileR.Open(L"d:\\data.lua", CFile::modeRead | CFile::typeBinary))
	{
		//return strFile;
	}
	BYTE head[3];
	fileR.Read(head, 3);
	if (!(head[0] == 0xEF && head[1] == 0xBB && head[2] == 0xBF))
	{
		fileR.SeekToBegin();
	}
	ULONGLONG FileSize = fileR.GetLength();
	char* pContent = (char*)calloc(FileSize + 1, sizeof(char));
	fileR.Read(pContent, FileSize);
	fileR.Close();
	int n = MultiByteToWideChar(CP_UTF8, 0, pContent, FileSize + 1, NULL, 0);
	wchar_t* pWideChar = (wchar_t*)calloc(n + 1, sizeof(wchar_t));
	MultiByteToWideChar(CP_UTF8, 0, pContent, FileSize + 1, pWideChar, n);
	strLua = CString(pWideChar);
	free(pContent);
	free(pWideChar);

	
	lua_register(L, "show", show);
	lua_register(L, "GetBindWindow", GetBindWindow);
	lua_register(L, "UnBindWindow", UnBindWindow);
	lua_register(L, "MoveTo", MoveTo);
	lua_register(L, "MoveToEx", MoveToEx);
	lua_register(L, "ClickEx", ClickEx);
	lua_register(L, "Click", Click);
	lua_register(L, "FindWindowEx", luaFindWindowEx);
	lua_register(L, "EnumProcess", EnumProcess);
	lua_register(L, "TerminateProcess", TerminateProcess);
	lua_register(L, "runScript", runScript);
	lua_register(L, "runScripts", runScripts);
	lua_register(L, "runScriptExs", runScriptExs);
	lua_register(L, "delay", delay);
	lua_register(L, "SetWindowState", SetWindowState);
	lua_register(L, "KeyPress", KeyPress);
	lua_register(L, "KeyDownChar", KeyDownChar);
	lua_register(L, "KeyUpChar", KeyUpChar);
	lua_register(L, "KeyPress", KeyPress);
	lua_register(L, "BindWindowEx", BindWindowEx);
	lua_register(L, "MoveWindow", luaMoveWindow);
	lua_register(L, "GetItemListText", GetItemListText);
	lua_register(L, "SetState", SetState);
	lua_register(L, "GetState", GetState);
	lua_register(L, "SetBossState", SetBossState);
	lua_register(L, "GetBossState", GetBossState);
	lua_register(L, "SetCheckState", SetCheckState);
	lua_register(L, "SetItemListText", SetItemListText);
	lua_register(L, "SetConfig", SetConfig);
	lua_register(L, "GetConfig", GetConfig);
	lua_register(L, "GetBossPoint", GetBossPoint);

	luaopen_base(L);
	luaL_openlibs(L);
	
	

}

// 脚本主线程,脚本的主要逻辑在这里处理
unsigned WINAPI MainThread(PVOID pParam)
{
	long index = (long)(DWORD_PTR)pParam;
	CDm * dm;
	// 初始化当前线程com组件为MTA模式
	CoInitializeEx(NULL, 0);
	g_info[index].thread_state = State_Runing;
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);
	// 创建对象
	g_info[index].dm = new CDm;
	
	dm = g_info[index].dm;

	// 检测对象是否创建成功,虽然这个一般不会失败,但为了程序健壮性考虑还是加上,如果内存吃紧，还是可能会失败
	if (dm == NULL || dm->Ver().GetLength() == 0)
	{
		Log(_T("对象创建失败"));
		ThreadNotifyUI_Post(NOTIFY_STOP, index);
		return 0;
	}
	// 开启全局共享字库
	dm->EnableShareDict(1);

	// 其他设置,比如路径等等 当前目录
	long ret = dm->SetPath(_T("c:\\MobileGame\\pic\\"));
	//g_main_cwnd->AppendText(L"绑定图片" + NumberToString(ret));
	dm->SetDict(0, L"jinbi.txt");
	dm->SetDict(1, L"code.txt");
	
	dm->SetShowErrorMsg(0);
	// 开始绑定,主绑定一定要第一个绑定,并且主绑定所在的线程绝对不能结束,否则会造成绑定失效
	//long dm_ret = dm->BindWindowEx(g_info[index].hwnd, _T("normal"), _T("normal"), _T("normal"), _T("dx.public.anti.api"), 0);
	//if (dm_ret != 1)
	//{
	//	Log(_T("主:绑定失败，错误码:%d"), dm->GetLastError());
	//	// 通知主线程进行结束操作(释放资源)
	//	ThreadNotifyUI_Post(NOTIFY_STOP, index);
	//	return 0;
	//}
	// 禁止输入
	//dm->LockInput(4);
	// 我们可以创建副线程了
	// 更新副线程信息
	g_info[index + MAX_HWND].thread_state = State_Starting;
	// 通知UI,副线程开始创建了
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index + MAX_HWND);
	// 创建副线程
	//调式测试
	g_info[index + MAX_HWND].handle = (HANDLE)_beginthreadex(0, 0, SubThread, (PVOID)(DWORD_PTR)(index + MAX_HWND), 0, 0);
	if (g_info[index + MAX_HWND].handle == NULL)
	{
		// 这里必须要解绑,因为模式0和2不在当前线程解绑的话,会导致无法解绑
		dm->UnBindWindow();

		Log(_T("创建副线程失败"));
		// 通知主线程进行结束操作(释放资源)
		ThreadNotifyUI_Post(NOTIFY_STOP, index);
		return 0;
	}
	g_bSwicth = false;
	
	int count = g_main_cwnd->m_list_info.GetItemCount();

	LoadLua();

	for (int i = 0; i < count; i++)
	{
		CString strState = g_main_cwnd->m_list_info.GetItemText(i, 6);
		if (strState != L"账号错误" &&
			strState != L"二密错误" &&
			strState != L"账号在线" &&
			strState != L"完成" &&
			strState != L"武器未装备")
		{
			int nCodeLine = g_IniFile.GetInt(L"Set", L"CodeLine");
			//g_main_cwnd->m_list_info.GetColumn();

			int nListCodeLine = _wtoi(g_main_cwnd->m_list_info.GetItemText(i, 12));
			if (nListCodeLine == 0) {
				nListCodeLine = _wtoi(g_main_cwnd->m_list_info.GetItemText(i, 11));
			}
			if (nCodeLine == -1) {//首次启动迅游
				g_main_cwnd->AppendText(L"首次启动线路:" + arrLineCode[1]);
				if (ChangeLine(arrLineCode[1])) {
					g_main_cwnd->AppendText(L"加速成功");
					g_IniFile.SetInt(L"Set", L"CodeLine", 1);
					g_main_cwnd->SetDlgItemTextW(IDC_EDIT3, L"1");
					//g_main_cwnd->GetDlgItem(IDC_STATIC5);
				}
				//取下标为0的线路
				//g_main_cwnd->
				//CListBox* list = (CListBox*)g_main_cwnd->GetDlgItem(IDC_LIST1);

				//启动成功后更新配置线路
			}
			else if (nCodeLine != -1 && nCodeLine != nListCodeLine)
			{
				isGif = true;//开启截屏处理
				long hwnd = g_dm->FindWindow(L"MapleStoryClass", L"MapleStory");
				if (hwnd != 0) {
					g_bSwicth = false;
					KillProcess(L"MapleStory.exe");
					ScriptDelay(index, 1000);
				}
				if (ChangeLine(arrLineCode[nListCodeLine])) {
					g_IniFile.SetInt(L"Set", L"CodeLine", nListCodeLine);
					g_main_cwnd->SetDlgItemTextW(IDC_EDIT3, NumberToString(nListCodeLine));
				}

				//取当前列表线路下标-1
				//根据线路换线
				//启动成功后更新配置线路
			}
			long hwnd = g_dm->FindWindowW(L"XunYouMainClass_4B32", L"迅游国际版");
			if (hwnd > 0) {
				g_dm->SetWindowState(hwnd, 2);
			}
			g_flag = true;
			DoWork(index, i, false);
		}
	}
	lua_close(L);
	return 0;
}

void DoWork(long index, int taskIndex, bool bLoginState)
{
	CDm *dm = g_info[index].dm;
	USES_CONVERSION;
	//函数T2A和W2A均支持ATL和MFC中的字符
	char* pFileName = T2A(strLua);
	//StrP()
	luaL_dostring(L, pFileName);
	lua_getglobal(L, "login");
	lua_pushlightuserdata(L, dm);
	lua_pushnumber(L, taskIndex);
	lua_pcall(L, 2, 1, 0);
}



void SetExcepState(long index, const TCHAR * state)
{
	_tcscpy(g_info[index].excep_state, state);
	ThreadNotifyUI_Post(NOTIFY_STOP, index);
}


// 脚本副线程,用于检测异常等
unsigned WINAPI SubThread(PVOID pParam)
{
	long index = (long)(DWORD_PTR)pParam;

	CDm * dm;

	// 初始化当前线程com组件为MTA模式
	CoInitializeEx(NULL, 0);

	g_info[index].thread_state = State_Runing;
	ThreadNotifyUI_Post(NOTIFY_UPDATE, index);

	// 创建对象
	g_info[index].dm = new CDm;
	dm = g_info[index].dm;

	// 检测对象是否创建成功,虽然这个一般不会失败,但为了程序健壮性考虑还是加上,如果内存吃紧，还是可能会失败
	if (dm == NULL || dm->Ver().GetLength() == 0)
	{
		Log(_T("对象创建失败"));
		SetExcepState(index, _T("对象创建失败"));
		return 0;
	}

	// 开启全局共享字库
	dm->EnableShareDict(1);
	dm->SetShowErrorMsg(0);
	// 其他设置,比如路径等等
	//dm->SetPath(_T("c:\test_game"));
	long ret = dm->SetPath(_T("c:\\MobileGame\\pic\\"));

	//g_info[index].dm->BindWindowEx(g_info[index].hwnd, L"normal", L"normal", L"normal", L"", 0);
	//long dm_ret = dm->BindWindowEx(g_info[index].hwnd, _T("normal"), _T("normal"), _T("dx"), _T("dx.public.anti.api"), 0);
	//if (dm_ret != 1)
	//{
	//	Log(_T("副:绑定失败，错误码:%d"), dm->GetLastError());
	//	// 通知主线程进行结束操作(释放资源)
	//	SetExcepState(index, _T("副:绑定失败"));
	//	return 0;
	//}


	while (1)
	{
		// 检测一些异常,比如突然弹出的对话框，目标窗口被关闭或者掉线等突发情况
		// 比如检测到掉线，可考虑通知UI,然后重新运行
		CheckException(index);
		//ScriptDelay(index, 3000);
	}
}

void CheckException(long index)
{
	long x, y;
	dmsoft * dm = g_info[index].dm;
	long hwnd = g_info[index].dm->FindWindow(L"MapleStoryClass", L"MapleStory");
	if (g_info[index].dm->GetBindWindow() != hwnd && g_info[index].dm->GetBindWindow()!=0) {
		g_info[index].dm->UnBindWindow();
	}
	if (g_info[index].dm->GetBindWindow() == 0 && hwnd!=0) {
		g_info[index].dm->BindWindowEx(hwnd, L"normal", L"normal", L"normal", L"", 0);

	}
	//是否开启检测窗口
	int nTime = 0;
	if (CheckState && g_flag) {
		if (hwnd == 0) {
			g_flag = false;	//窗口不存在则程序中断
			CheckState = false;//检查窗口为假等待下次设定
		}

		if (g_BossState) {
			if (dm->GetColor(545, 712) == L"f0f0f0") {
				if (dm->GetColor(567, 720) == L"9e9da0") {
					//g_main_cwnd->AppendText(L"补血");
					dm->KeyPress(35);
				}
			}
			else {
				if (dm->GetColor(567, 736) == L"9e9da0") {
					//g_main_cwnd->AppendText(L"补血");
					dm->KeyPress(35);
				}
			}
			//showText(L"检测线程开始");
			dm->FindColorBlock(0, 228, 1024, 580, L"292222-101010", 0.98, 3000, 150, 50, &x, &y);
			//g_nBossX = RandomNumber(1,1024);
			g_nBossX = x;
			Sleep(150);
		}

		if (g_main_cwnd->m_ZhaKun.GetCheck() == 1) {
			nTime = GetTickCount();
			if (dm->IsDisplayDead(0, 760, 14, 769, 1) == 1) {
				//nCountTime++;
				gTime = gTime + (GetTickCount() - nTime) / 1000;
			}
			else {
				gTime = 0;
			}
			if (gTime > 180) {
				//如果当前的配置已经存在则角色为下一角色
				//获取配置账号
				CString strRole = NumberToString(gnIndex) + L"," + g_main_cwnd->m_list_info.GetItemText(gnIndex, 7);
				CString strRole1 = g_IniFile.GetString(NumberToString(gnIndex + 1), L"RoleCode");
				g_main_cwnd->AppendText(L"当前角色:" + strRole + L"配置角色:" + strRole1);
				if (strRole == strRole1) {
					int nRoleNum = g_AccountFile.GetInt(NumberToString(gnIndex + 1), L"RoleNum");
					int nZhaNum = g_AccountFile.GetInt(NumberToString(gnIndex + 1), L"ZhaNum");
					if (nRoleNum == nZhaNum) {//切换账号
						g_main_cwnd->m_list_info.SetItemText(gnIndex, 6, L"完成");
						g_AccountFile.SetString(NumberToString(gnIndex + 1), L"state", L"1");
					}
					else {
						++nRoleNum;
						g_AccountFile.SetInt(NumberToString(gnIndex + 1), L"RoleNum", nRoleNum);
						g_main_cwnd->m_list_info.SetItemText(gnIndex, 7, NumberToString(nRoleNum));
					}
				}
				g_IniFile.SetString(NumberToString(gnIndex + 1), L"RoleCode", NumberToString(gnIndex) + L"," + g_main_cwnd->m_list_info.GetItemText(gnIndex, 7));
				gTime = 0;
				KillProcess(L"MapleStory.exe");
				g_flag = false;
			}
			if (gTime == 170) {
				CString str; //获取系统时间 　　
				//CTime tm; 
				//tm = CTime::GetCurrentTime();
				//str = tm.Format("%H%M%S");
				str = g_main_cwnd->m_list_info.GetItemText(gnIndex, 1) + g_main_cwnd->m_list_info.GetItemText(gnIndex, 7);
				//dm->CaptureGif(0, 0, 1280, 960, L"d:\\pic\\" + str + L".gif", 100, 10000);
				//Sleep(30000)
			}
			g_main_cwnd->AppendText(L"运行状态:" + NumberToString(g_flag) + L"检测状态:" + NumberToString(CheckState) + L"时间间隔" + NumberToString(gTime));

		}
	}

	



	//进入扎昆地图开始截图
	CString str; //获取系统时间 　　
	CTime tm; tm = CTime::GetCurrentTime();
	str = tm.Format("%H%M%S");
	if (isGif) {
		//dm->CaptureGif(135, 150, 1239, 768, L"d:\\pic\\line"+str + L".gif", 100, 40000);
		isGif = false;
	}

	//dm->FindPic(0, 0, 310, 88, L"mapsiwu.bmp", L"050505", 1, 0, &x, &y);
	//if (x > 0) {
	//	str = L"d:\\pic\\" + str + L".gif";
	//	dm->CaptureGif(200, 400, 1280, 960 - 40, str, 100, 30000);
	//}
	


	if (g_bloodState) {
		//g_main_cwnd->AppendText(L"补血颜色1："+ g_info[index].dm->GetColor(545, 712)+L"补血颜色2"+ dm->GetColor(567, 720));
		if (g_info[index].dm->GetColor(545, 712) == L"f0f0f0") {
			if (g_info[index].dm->GetColor(567, 720) == L"9e9da0") {
				//g_main_cwnd->AppendText(L"补血");
				g_info[index].dm->KeyPress(35);
			}
		}
		else {
			if (g_info[index].dm->GetColor(567, 736) == L"9e9da0") {
				g_main_cwnd->AppendText(L"补血");
				g_info[index].dm->KeyPress(35);
			}
		}
		ScriptDelay(index, 1000);
	}
	ScriptDelay(index, 1000);



	//任务开始时检查窗口是否存在

	//if (dm->CmpColor(579, 717, L"fb6bd1", 0.8) == 1) {
	//	dm->KeyPress(35);
	//	ScriptDelay(index,1000);
	//	//moveKey(35, 300, 200);
	//}


	//// 检测窗口是否存在
	//if (dm->GetWindowState(g_info[index].hwnd, 0) == 0)
	//{
	//	SetExcepState(index, _T("窗口不见了"));
	//}

	// 检测窗口是否卡死



	// 检测是否掉线


	// 检测是否有弹出窗口



	// 其他检测
	//dm->KeyPressChar(_T("s"));
}


void moveKey(long index,int key, int keyDelay) {
	g_info[index].dm->KeyDown(key);
	g_info[index].dm->delay(keyDelay);
	g_info[index].dm->KeyUp(key);
	g_info[index].dm->delay(keyDelay);
}

void CloseWindows() {

	HANDLE hToken;
	TOKEN_PRIVILEGES tkp;
	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
	{
		
		g_main_cwnd->MessageBox(_T("关机失败..."), _T("警告"), MB_OK);
		return;
	}
	LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,
		&tkp.Privileges[0].Luid);
	tkp.PrivilegeCount = 1;
	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
	AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, NULL);
	if (GetLastError() != ERROR_SUCCESS)
	{
		g_main_cwnd->MessageBox(_T("关机失败..."), _T("警告"), MB_OK);
		return;
	}
	ExitWindowsEx(EWX_SHUTDOWN | EWX_FORCE, 0);

}